#include "gsm.h"
#include "gsmio.h"

static const char* GSMIO_HTTP_STR  = "Content-Length: ";
static const int   GSMIO_HTTP_STRL = 16;

static const char* GSMIO_CRC32_STR  = "X-CRC: ";
static const int   GSMIO_CRC32_STRL = 7;

static const char*  GSMIO_FORMAT_STR  ="FormatSD";
static const int    GSMIO_FORMAT_STRL = sizeof(GSMIO_FORMAT_STR)-1;

static unsigned int gsmio_tcp_receive(unsigned long* timeout_ms);

static volatile unsigned int  gsmioerror;

static volatile unsigned char IOBuff[2048];

GSM_CMD_t gsmio_command(char* cmd, char* resp, int timeout_ms)
{
  return gsmio_command_n(cmd, strlen(cmd), resp, timeout_ms, 1);
}

GSM_CMD_t gsmio_command_n(char* cmd, int len, char* resp, int timeout_ms, char flush)
{
  int j = 0;
  char word[64] = "";
 
  if (flush) modem_flush();
  if (len > 0)
    modem_putn(cmd, len);
  //debug_printf("%s\r\n", cmd);
  while (1){
    char data = 0;
    if (timeout_ms <= 0) 
      return GSM_CMD_TIMEOUT;
          
    if (!modem_read(&data, 1)){
      ctl_timeout_wait(ctl_get_current_time()+ctl_get_ticks_per_second()/100);
      timeout_ms -= 10;
      continue;
    }

    if (data=='>' && strcmp(">", resp)==0) return GSM_CMD_OK;
    if (data=='\r' || data=='\n') {
      word[j] = 0;
      //debug_printf("%s\r\n", word);
      if (j > 0 && strcmp(word, resp) == 0){
        return GSM_CMD_OK;
      }
      j = 0;
      continue;
    }
    word[j] = data;
    j += 1;
  }
}

unsigned int gsmio_tcp_receive(unsigned long* timeout_ms)
{
  unsigned int size = 0; // Bytes to read
  char s = 0; // State: 0 - '+', 1 - 'I', 2 - 'P', 3- 'D', 4 - length and ':', 6 - data
  char c = 0; // Input char from modem

  while (*timeout_ms){
    if (!modem_read(&c, 1)) {
      ctl_timeout_wait(ctl_get_current_time()+ctl_get_ticks_per_second()/1000);
      *timeout_ms -= 1;
      continue;
    }
    switch(s) {
      case 0:
        if (c == '+') s = 1;
      break;
      case 1:
        if (c == 'I') s = 2;
        else if (c == '+') s = 1;
        else s = 0;
      break;
      case 2:
        if (c == 'P') s = 3;
        else s = 0;
      break;
#ifdef SIM300
      case 3:
        if (c == 'D') s = 5;
        else s = 0;
      break;
#else
      case 3:
        if (c == 'D') s = 4;
        else s = 0;
      break;
      case 4:
        if (c == ',') s = 5;
        else s = 0;
      break;
#endif
      case 5:
        if (c >= '0' && c <= '9') size = size*10 + (c - '0');
        else if (c == ':') 
          return size;
        else s = 0;
    }
  } 
  return 0;
}

/*
GSM_CMD_t gsmio_json_receive(unsigned long timeout_ms, json_node** output)
{
  char crypt[8] = ""; // 64-bit crypt block 
  unsigned char block = 0; // Current block position

  json_parse_init();
  unsigned int btr = gsmio_tcp_receive(&timeout_ms); // Bytes to read
  while (timeout_ms && btr){
    if (!modem_read(&crypt[block], 1)) {
      ctl_timeout_wait(ctl_get_current_time()+ctl_get_ticks_per_second()/1000);
      timeout_ms -= 1;
      continue;
    }   
    block++;

    if (block >= 8){ //Block complete, decrypt...
      block = 0;
      rtea_decrypt_block((unsigned int*)crypt, RTEA_KEY);
      for (int i = 0; i < 8; i++){
        if (json_parse_char(crypt[i], output)) 
          return GSM_CMD_OK;
      }
    }
    if (--btr == 0) break;
  } // while (timeout_ms)...

  if (timeout_ms > 0 && btr > 0) // Timeout and chars left
    return GSM_CMD_TIMEOUT;

  return GSM_CMD_ERROR;
}
*/
static unsigned long timeout_ms;  // чтоб было всегда видно в отладчике
GSM_CMD_t gsmio_http_receive(FIL* file, unsigned int *crc32, unsigned long tms)
{
  unsigned char state   = 0; //0 - Content-Length read, 1 - \r\n\r\n read, 2 - data read
  unsigned long length  = 0xfacefeed;
  unsigned long buff_p  = 0;
  unsigned char* buffer;// (unsigned char*)calloc(1, 1500);// = EMC_EXT_MEM; // пидары вонючие!!!
  unsigned  int wdtres; // счетчик для сброса WDT
  timeout_ms=tms;
  buffer=IOBuff;
  gsmioerror=0;
  if (buffer == NULL) return GSM_CMD_ERROR;
  wdtres=0;
  while (timeout_ms){
    unsigned int btr = gsmio_tcp_receive(&timeout_ms); // Get block size
    buff_p = 0;
    char line[128] = "";
    unsigned char pos = 0;
    while(timeout_ms && btr) {
      wdtres++;
      if(wdtres>500){ // если от модема ничего не приходит то долго кручусь в этом цикле
        WDT_RESET();
        wdtres=0;
      }
      char c = 0;
      if (!modem_read(&c, 1)) {
        ctl_timeout_wait(ctl_get_current_time()+ctl_get_ticks_per_second()/1000);
        timeout_ms -= 1;
        continue;
      }
      
      if (state == 0) {
        if (c == '\r' || c == '\n') {
          line[pos + 1] = 0;
          if (strncmp(line, GSMIO_HTTP_STR, GSMIO_HTTP_STRL) == 0) {
            length = 0;
            for (unsigned char i = GSMIO_HTTP_STRL; i < pos; i++){
              if (line[i] >= '0' && line[i] <= '9') 
                length = length*10 + (line[i] - '0');
            }
 //           debug_printf("LENGTH HTTP: %u\r\n", length);
          }
          if (strncmp(line, GSMIO_CRC32_STR, GSMIO_CRC32_STRL) == 0) {
            unsigned int v = 0;
            for (unsigned char i = GSMIO_CRC32_STRL; i < pos; i++){
              if (line[i] >= '0' && line[i] <= '9') 
                v = v*10 + (line[i] - '0');
            }
            *crc32 = v;
//            debug_printf("CRC32 HTTP: %u\r\n", v);
            state = 1;
          }

          if (strncmp(line, GSMIO_FORMAT_STR, GSMIO_FORMAT_STRL) == 0) {// найден параметр Format, файл не принимаю, обрываю связь и форматирую SD
            state = 5;
            timeout_ms=0;
            buff_p=0;
            length=0;
          }

          pos = 0;
        }
        else {
          if (pos > 127) pos = 0;
          line[pos++] = c;
        }
      }
      else if (state == 1) {
        if (c == '\r' || c == '\n') {
          if (++pos >= 4) state = 2;
        }
        else pos = 0;
      }
      else if (state == 2) {
        buffer[buff_p++] = c;
        length--;
      }
      btr--;
    }
    if (buff_p){
      unsigned int bw;
      WDT_RESET();
      FRESULT fr = f_write(file, buffer, buff_p, &bw);
      if (fr != FR_OK || bw != buff_p){gsmioerror=1;};
    }
    if (length == 0) break;
  }
  if(state==5)return GSM_CMD_FORMAT;
  //if (buffer != NULL) free(buffer);
  if (timeout_ms == 0){gsmioerror=2; return GSM_CMD_TIMEOUT;}
  if (length != 0){gsmioerror=3; return GSM_CMD_ERROR;}
  return GSM_CMD_OK;
}

void gsmio_power_on()
{
  GSMIO_PULLUPS_OFF();
  MODEM_ENABLE_RXD_PIN(); // Enable only RXD pin to avoid "phantom-power"
  MODEM_CLR_RTS();        // Clear GSM modem RTS to allow receive data
  MODEM_CLR_DTR();
  GSMIO_POWER_ON();
  delay_ms(100);
}

void gsmio_power_off()
{
  GSMIO_POWER_OFF();
  delay_ms(3000);
}

void gsmio_on(){
  GSMIO_CLR_KEY();
  delay_ms(1500);
  GSMIO_SET_KEY();
  MODEM_ENABLE_TXD_PIN();
  MODEM_ENABLE_CTS_PIN();
  modem_puts("AT\r\n");
  delay_ms(1000);
  modem_puts("AT+IPR=19200\r\n");
  delay_ms(1000);
  modem_puts("AT&W\r\n");
//  delay_ms(1000);
//  modem_puts("AT+IFC=0,0\r\n");
//  delay_ms(1000);
  modem_puts("AT+IPR?\r\n");
  delay_ms(1000);
//  ctl_timeout_wait(ctl_get_current_time()+3*ctl_get_ticks_per_second());
  
  //gsmio_command("", "Call Ready", 90000); // Wait for modem power up
  gsmio_command("", "Call Ready", 30000); // Wait for modem power up
  MODEM_ENABLE_TXD_PIN();
  MODEM_ENABLE_CTS_PIN();

#if 0
/*
  int i;
  MODEM_ENABLE_TXD_PIN();
  MODEM_ENABLE_CTS_PIN();
  GSMIO_CLR_KEY();
  delay_ms(1500);
  GSMIO_SET_KEY();
  MODEM_ENABLE_TXD_PIN();
  MODEM_ENABLE_CTS_PIN();
  delay_ms(200);
  modem_puts("AT+IPR=0\r\n");
  MODEM_SET_RTS();
  modem_puts("AT+IPR=0\r\n");
  delay_ms(2200);
  MODEM_CLR_RTS();
  modem_puts("AT+IPR=0\r\n");
  delay_ms(1000);
  modem_puts("AT\r\n");
  delay_ms(200);
//  modem_puts(SetBaudSrt);
  delay_ms(200);
//  modem_puts("AT+IPR=19200\r\n");
//  modem_puts("AT&W\r\n");
//  delay_ms(1000);
//  modem_puts("AT+IFC=0,0\r\n");
//  delay_ms(1000);
  for(i=0;i<100;i++){
    modem_puts("AT+IPR?\r\n");
    delay_ms(300);
  }
//  ctl_timeout_wait(ctl_get_current_time()+3*ctl_get_ticks_per_second());
  
  //gsmio_command("", "Call Ready", 90000); // Wait for modem power up
  gsmio_command("", "Call Ready", 30000); // Wait for modem power up
  MODEM_ENABLE_TXD_PIN();
  MODEM_ENABLE_CTS_PIN();
*/
#endif
}

#if (HW_ver==4 )||(HW_ver==5)

void  GSMIO_PULLUPS_OFF(void){
  PINMODE4 = (PINMODE4 & ~0x0000FFFF) | 0x0000AAAA;
}

void  GSMIO_POWER_ON(void){
  GSM_PWR_DIRPORT |= (1l<<(GSM_PWR_ON_PIN));
  GSM_PWR_ON_CLRPORT =  (1l<<(GSM_PWR_ON_PIN));
}
void  GSMIO_POWER_OFF(void){
/*  SCS|=1;
  FIO2MASK=0;
  PCLKSEL0=0xAAAAAAAA;
  PCLKSEL1=0xAAAAAAAA;
  PINSEL4=0;
  PINMODE4=0xAAAA;
  FIO2DIR=0x100;
  FIO2PIN=0x100;*/
  GSM_PWR_DIRPORT |= (1l<<GSM_PWR_ON_PIN);
  GSM_PWR_ON_SETPORT =  (1l<<GSM_PWR_ON_PIN);
/*
// подача питания на модем
#define GSM_PWR_ON_PIN      8
#define GSM_PWR_DIRPORT     FIO2DIR
#define GSM_PWR_ON_SETPORT  FIO2SET
#define GSM_PWR_ON_CLRPORT  FIO2CLR
*/
/*
  FIO2DIR=0x100;
  FIO2SET=0x100;

  *((unsigned int*)0x3FFFC040)=0x100;
  *((unsigned int*)0x3FFFC058)=0x100;
  *((unsigned int*)0xE002C010)  // PINSEL4
  *((unsigned int*)0xE002C050)  // PINMODE4
  *((unsigned int*)0xE01FC040)
*/
  delay_ms(1000);
}

void  GSMIO_SET_KEY(void){
  GSM_KEY_DIRPORT |= (1l<<GSM_KEY_PIN);
  GSM_KEY_SETPORT =  (1l<<GSM_KEY_PIN);
}
void GSMIO_CLR_KEY(){
  GSM_KEY_DIRPORT |= (1l<<GSM_KEY_PIN);
  GSM_KEY_CLRPORT =  (1l<<GSM_KEY_PIN);
}

void GSMIO_SIM(GSM_SIM_t n){
  if(n==GSM_SIM1)GSMIO_SIM1();
  else GSMIO_SIM2();
}
void GSMIO_SIM2(void){
  GSM_SIM_DIRPORT |= (1l<<GSM_SIM_PIN); GSM_SIM_SETPORT =  (1l<<GSM_SIM_PIN);
}
void GSMIO_SIM1(){
  GSM_SIM_DIRPORT |= (1l<<GSM_SIM_PIN);
  GSM_SIM_CLRPORT =  (1l<<GSM_SIM_PIN);
}

#endif